package com.cloud.pole.common.util.jwt;

import io.jsonwebtoken.*;
import org.joda.time.DateTime;
import org.springframework.stereotype.Component;
import com.cloud.pole.common.constant.CacheConstant;
import com.cloud.pole.common.constant.CommonConstants;
import com.cloud.pole.common.exception.auth.UserTokenException;
import com.cloud.pole.common.util.StringHelper;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;

/**
 * jwt 工具类
 */
@Component
public class JwtTokenUtil {
	//永久不失效
	public static final int TOKEN_NOT_EXPIRE = -1;
    
	/**
     * 密钥加密token
     *
     * @param jwtInfo
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(IJWTInfo jwtInfo, int expire) {
        try {
            JwtBuilder builder = Jwts.builder()
                    .setSubject(jwtInfo.getUniqueName())
                    .claim(CommonConstants.JWT_KEY_USER_TYPE, jwtInfo.getType())
                    .claim(CommonConstants.JWT_KEY_USER_ID, jwtInfo.getId())
                    .claim(CommonConstants.JWT_KEY_NICK_NAME, jwtInfo.getNickName())
                    .claim(CommonConstants.JWT_KEY_REAL_NAME, jwtInfo.getName())
                    .claim(CommonConstants.JWT_KEY_ATTR_1, jwtInfo.getAttr1())
                    .claim(CommonConstants.JWT_KEY_ATTR_2, jwtInfo.getAttr2())
                    .claim(CommonConstants.JWT_KEY_ATTR_3, jwtInfo.getAttr3())
                    .claim(CommonConstants.JWT_KEY_ATTR_4, jwtInfo.getAttr4())
                    .signWith(SignatureAlgorithm.HS256, getKeyInstance());
            if (expire > 0) {
                builder.setExpiration(DateTime.now().plusSeconds(expire).toDate());
            }
            String compactJws = builder.compact();
            return compactJws;
        } catch (Exception e) {
        	e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 密钥加密token
     *
     * @param jwtInfo
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(IJWTInfo jwtInfo) {
        try {
            JwtBuilder builder = Jwts.builder()
                    .setSubject(jwtInfo.getUniqueName())
                    .claim(CommonConstants.JWT_KEY_USER_TYPE, jwtInfo.getType())
                    .claim(CommonConstants.JWT_KEY_USER_ID, jwtInfo.getId())
                    .claim(CommonConstants.JWT_KEY_NICK_NAME, jwtInfo.getNickName())
                    .claim(CommonConstants.JWT_KEY_ATTR_1, jwtInfo.getAttr1())
                    .claim(CommonConstants.JWT_KEY_ATTR_2, jwtInfo.getAttr2())
                    .claim(CommonConstants.JWT_KEY_ATTR_3, jwtInfo.getAttr3())
                    .claim(CommonConstants.JWT_KEY_ATTR_4, jwtInfo.getAttr4())
                    .signWith(SignatureAlgorithm.HS256, getKeyInstance());
            String compactJws = builder.compact();
            return compactJws;
        } catch (Exception e) {
        	e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * @return
     */
    private static Key getKeyInstance() {
        //We will sign our JavaWebToken with our ApiKey secret
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(CommonConstants.TOKEN_SECRET);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        return signingKey;
    }

    /**
     * 公钥解析token
     *
     * @param token
     * @return
     * @throws Exception
     */
    private static Jws<Claims> parserToken(String token) throws Exception {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
        return claimsJws;
    }

    /**
     * 获取token中的用户信息
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static IJWTInfo getInfoFromToken(String token) throws Exception {
        try {
            Jws<Claims> claimsJws = parserToken(token);
            Claims body = claimsJws.getBody();
            JWTInfo info = new JWTInfo( 
            		body.getSubject(), 
            		Integer.parseInt(StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_TYPE))),
            		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_ID)), 
            		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_NICK_NAME)),
            		StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_REAL_NAME)));
            info.setUserAttr1(StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_ATTR_1)));
            info.setUserAttr2(StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_ATTR_2)));
            info.setUserAttr3(StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_ATTR_3)));
            info.setUserAttr4(StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_ATTR_4)));
            return info;
        }
        catch (ExpiredJwtException ex) {
            throw new UserTokenException("token expired!");
        } catch (SignatureException ex) {
            throw new UserTokenException("token signature error!");
        } catch (IllegalArgumentException ex) {
            throw new UserTokenException("token is null or empty!");
        }
    }


    public static void main(String[] args) throws Exception {
    	JWTInfo info = new JWTInfo("8613755002297", 20, "1805", "昵称", "陈胜良");
    	info.setUserAttr1("userAttr1");
    	info.setUserAttr2("userAttr2");
    	info.setUserAttr3("userAttr3");
    	info.setUserAttr4("userAttr4");
    	
        String str = generateToken(info, 60000);
        System.out.println(str);
        

        IJWTInfo toInfo = getInfoFromToken("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4NjEzNzU1MDAyMjk3IiwidXNlclR5cGUiOjMwLCJ1c2VySWQiOiIxODQ5Iiwibmlja05hbWUiOiLpmYjog5zoia8iLCJyZWFsTmFtZSI6IumZiOiDnOiJryIsImF0dHIxIjoiNjQiLCJleHAiOjE1NjUwOTc4NTh9.cW-9ICrWioAtjLk0YnDpQ8jolMTURM2lw3UbO7O-VpM");
//        IJWTInfo toInfo = getInfoFromToken(str);
        System.out.println(toInfo.getId());
        System.out.println(toInfo.getName());
        System.out.println(toInfo.getNickName());
        System.out.println(toInfo.getType());
        System.out.println(toInfo.getAttr1());
        System.out.println(toInfo.getAttr2());
        System.out.println(toInfo.getAttr3());
    }
}
